package org.zoomdev.zoom.timer.modules;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zoomdev.zoom.aop.MethodInvokerFactory;
import org.zoomdev.zoom.aop.annotations.NoEnhance;
import org.zoomdev.zoom.common.Destroyable;
import org.zoomdev.zoom.common.config.ConfigReader;
import org.zoomdev.zoom.common.exceptions.ZoomException;
import org.zoomdev.zoom.common.res.ResScanner;
import org.zoomdev.zoom.common.utils.CachedClasses;
import org.zoomdev.zoom.common.utils.Classes;
import org.zoomdev.zoom.ioc.Ioc;
import org.zoomdev.zoom.ioc.annotations.IocBean;
import org.zoomdev.zoom.ioc.annotations.Module;
import org.zoomdev.zoom.ioc.annotations.ModuleInit;
import org.zoomdev.zoom.timer.TimerJob;
import org.zoomdev.zoom.timer.TimerService;
import org.zoomdev.zoom.timer.annotation.Timer;
import org.zoomdev.zoom.timer.impl.QuartzTimerService;

import java.lang.reflect.Method;
import java.util.List;

@NoEnhance
@Module()
public final class CoreTimerModule implements Destroyable {

    public static final String NAME = "TIMER_MODULE";

    private static final Logger log = LoggerFactory.getLogger(CoreTimerModule.NAME);


    public static boolean enableLog;


    @IocBean
    public TimerService getTimerService() {
        log.info("=============Timer service starting...=============");
        return new QuartzTimerService();
    }

    /**
     * 理论上来讲，只要ioc里面有，那么就不会空
     * 这个最后执行
     *
     * @param ioc
     * @param scanner
     */
    @ModuleInit(after = true, async = true)
    public void config(Ioc ioc, MethodInvokerFactory invokerFactory, ConfigReader reader, ResScanner scanner, TimerService timerService) {
        String searchPath = reader.getString("zoom.scan.timer");
        if (StringUtils.isEmpty(searchPath)) {
            searchPath = "!java*&!sun*&(*.services.*|*Service|*.Job|*.Model)";
        }

        List<ResScanner.ClassRes> classes = scanner.findClass(searchPath);
        for (ResScanner.ClassRes res : classes) {
            Class<?> modelClass = res.getType();
            if (modelClass.isInterface()) {
                //先不处理 interface
                continue;
            }
            Method[] methods = CachedClasses.getPublicMethods(modelClass);
            for (Method method : methods) {
                Timer timer = method.getAnnotation(Timer.class);
                if (timer == null) {
                    continue;
                }
                String methodDesc = Classes.getMethodDesc(method);

                String cron = (String) reader.parseValue(getCron(timer));
                if (StringUtils.isEmpty(cron)) {
                    log.warn("Corn is empty: {} config:{}", methodDesc, timer.value());
                    continue;
                }

                timerService.start(method.toString(), createJob(ioc, modelClass, method, timer, methodDesc, cron), cron);
            }
        }


        log.info("=============Timer service started successfully=============");
    }

    private String getCron(Timer timer) {
        if (timer.every() != Timer.Every.NONE) {
            assert (timer.everyValue() > 0);
            if (timer.every() == Timer.Every.SECOND) {
                return String.format("0/%d * * * * ?", timer.everyValue());
            }
            if (timer.every() == Timer.Every.MINUTE) {
                return String.format("0 0/%d * * * ?", timer.everyValue());
            }
            if (timer.every() == Timer.Every.HOUR) {
                return String.format("0 0 0/%d * * ?", timer.everyValue());
            }
        }
        return timer.value();
    }

    private TimerJob createJob(Ioc ioc, Class modelClass, Method method, Timer timer, String methodDesc, String cron) {
        log.info("Start timer: {},Description: {},time cron:{}", methodDesc, timer.comment(), cron);
        Timer.Strategy strategy = timer.strategy();
        TimerJob job = new InvokerTimerJob(ioc, modelClass, method);
        switch (strategy) {
            case NONE:
                return job;
            case ABANDON:
                return new AbandonExistsStrategy(job);
            case WAIT:
                return new WaitExistsStrategy(job);
            default:
                throw new ZoomException("不支持的strategy");
        }

    }

    @Override
    public void destroy() {

    }


}
